/*
 * Copyright (c) 2001, 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 */
#include "StdAfx.h"

class WrapperClientUser : public ClientUser
{
public:
	WrapperClientUser(JNIEnv* env, jobject jClientUser)
	{
		this->env = env;
		this->jClientUser = env->NewGlobalRef(jClientUser);
	}

	~WrapperClientUser()
	{
		env->DeleteGlobalRef(jClientUser);
	}

	virtual void InputData(StrBuf* strbuf, Error* err)
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "inputData", "(Lnet/sourceforge/perforce/api/IError;)Ljava/lang/String;");		

		jobject jError = wrapError(err);
		
		jstring jResult = (jstring)env->CallObjectMethod(jClientUser, method, jError);
		if (env->ExceptionOccurred())
			return;

		const char* result = env->GetStringUTFChars(jResult, JNI_FALSE);
		
		strbuf->Clear();
		strbuf->Append(result);

		env->ReleaseStringUTFChars(jResult, result);
		unwrapError(jError, err);
	}

	virtual void HandleError(Error* err)
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "handleError", "(Lnet/sourceforge/perforce/api/IError;)V");

		jobject jError = wrapError(err);

		env->CallVoidMethod(jClientUser, method, jError);

		unwrapError(jError, err);
	}

	virtual void Message(Error* err)
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "message", "(Lnet/sourceforge/perforce/api/IError;)V");

		jobject jError = wrapError(err);

		env->CallVoidMethod(jClientUser, method, jError);

		unwrapError(jError, err);
	}

	virtual void OutputError(const_char* errBuf)
	{				
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "outputError", "(Ljava/lang/String;)V");

		env->CallVoidMethod(jClientUser, method, env->NewStringUTF(errBuf));
	}

	virtual void OutputInfo(char level, const_char* infoBuf)
	{				
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "outputInfo", "(CLjava/lang/String;)V");

		env->CallVoidMethod(jClientUser, method, level, env->NewStringUTF(infoBuf));
	}

	virtual void OutputText(const_char* data, int length)
	{
		if (env->ExceptionOccurred())
			return;

		jbyteArray byteArray = env->NewByteArray(length);
		env->SetByteArrayRegion(byteArray, 0, length, (signed char*)data);

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "outputText", "([B)V");

		env->CallVoidMethod(jClientUser, method, byteArray);
	}

	virtual void OutputStat(StrDict* varList)
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->FindClass("java/util/HashMap");
		jmethodID init = env->GetMethodID(clazz, "<init>", "()V");
		jobject propertyMap = env->NewObject(clazz, init);
		jmethodID putMethod = env->GetMethodID(clazz, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

		StrRef key;
		StrRef value;

		int i = 0;
		while (varList->GetVar(i++, key, value) != 0)
		{
			jstring keyString = env->NewStringUTF(key.Text());
			jstring valueString = env->NewStringUTF(value.Text());

			env->CallObjectMethod(propertyMap, putMethod, keyString, valueString);
		}

		jclass objectClass = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(objectClass, "outputStat", "(Ljava/util/Map;)V");

		env->CallVoidMethod(jClientUser, method, propertyMap);
	}

	virtual void Prompt(const StrPtr& msg, StrBuf& rsp, int noEcho, Error* err)
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "prompt", "(Ljava/lang/String;ZLnet/sourceforge/perforce/api/IError;)Ljava/lang/String;");

		jstring msgString = env->NewStringUTF(msg.Text());
		jobject jError = wrapError(err);

		jstring jResult = (jstring)env->CallObjectMethod(jClientUser, method, msgString, noEcho ? JNI_TRUE : JNI_FALSE, jError);
		const char* result = env->GetStringUTFChars(jResult, JNI_FALSE);

		rsp.Clear();
		rsp.Append(result);

		env->ReleaseStringUTFChars(jResult, result);
		unwrapError(jError, err);
	}

	virtual void ErrorPause(char* errBuf, Error* err)
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "errorPause", "(Ljava/lang/String;Lnet/sourceforge/perforce/api/IError;)V");

		jstring message = env->NewStringUTF(errBuf);
		jobject jError = wrapError(err);

		env->CallVoidMethod(jClientUser, method, message, jError);

		unwrapError(jError, err);
	}

	virtual void Finished() 
	{
		if (env->ExceptionOccurred())
			return;

		jclass clazz = env->GetObjectClass(jClientUser);
		jmethodID method = env->GetMethodID(clazz, "finished", "()V");

		env->CallVoidMethod(jClientUser, method);
	}

private:
	JNIEnv* env;
	jobject jClientUser;

	jobject wrapError(Error* err)
	{
		jclass clazz = env->FindClass("net/sourceforge/perforce/api/internal/Error");
		jmethodID init = env->GetMethodID(clazz, "<init>", "()V");
		
		jobject jError = env->NewObject(clazz, init);
		setNativeHandle(env, jError, err);

		return jError;
	}

	void unwrapError(jobject jError, Error* err)
	{
		setNativeHandle(env, jError, NULL);
	}
};
                       
JNIEXPORT void JNICALL Java_net_sourceforge_perforce_api_internal_ClientUser_construct(JNIEnv* env, jobject jClientUser)
{
	setNativeHandle(env, jClientUser, new WrapperClientUser(env, jClientUser));
}

JNIEXPORT void JNICALL Java_net_sourceforge_perforce_api_internal_ClientUser_destruct(JNIEnv* env, jobject jClientUser)
{
	ClientUser* clientUser = (ClientUser*)getNativeHandle(env, jClientUser);
	setNativeHandle(env, jClientUser, NULL);

	delete clientUser;
}
